feat: Verify per-context private attributes are not applied to other contexts - #430
Conversation
…contexts Co-Authored-By: rlamb@launchdarkly.com <4955475+kinyoklion@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
joker23
left a comment
There was a problem hiding this comment.
assuming this is the same as the v3 PR
|
Yes — identical to #429 apart from the v2 branch's data source naming ( I opened both because most SDKs' CI pulls the harness from |
SDK validationRan the 3 new subtests ( No SDK fails the new tests, and no SDK gains a new failure. 18 services PASS, 2 N/A (no/incapable test service), 2 BLOCKED (need a macOS runner / a physical Roku), 1 pending. Negative control: reverting launchdarkly/ruby-server-sdk#416 ( Per-SDK results
Each PASS row was checked to have actually executed the new subtests ( Rollout note: several repos pin a released harness rather than a branch tip (dotnet downloads the latest v2 release; python/go/java/dotnet pin |
|
Addendum — the js-core client-side workspaces finished, all PASS with no new failures (js-core
That closes out the run: 24 services PASS, 2 N/A (standalone |
🤖 I have created a release *beep* *boop* --- ## [2.41.0](v2.40.0...v2.41.0) (2026-08-19) ### Features * Verify per-context private attributes are not applied to other contexts ([#430](#430)) ([4d9b3a6](4d9b3a6)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Overview** > **Release 2.41.0** bumps the package version from **2.40.0** to **2.41.0** in the release manifest, `main.go` `versionString`, and **CHANGELOG**. > > The changelog entry for this release documents the main functional change shipped in this version: **contract tests** (from #430) that verify **per-context `_meta.privateAttributes` are scoped to that context only**—including that private attrs on one context or kind are **not** incorrectly applied when later events use other contexts or other kinds in a multi-context. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c5f9c21. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Adds contract coverage for private attributes declared in a context's
_meta.privateAttributesleaking into an SDK's globally configured private attribute list, so they get applied to unrelated contexts.v2line. Nearly every SDK's CI pulls the harness fromv2(ruby, php, erlang, rust, haskell, java, dotnet, ios, android, flutter, roku, node-client), so without this the regression below is untested for those SDKs.events/context properties; runs for server-side, client-side and PHP suites. No existing test or expectation changed.ContextFilterdid@private_attributes.concat(context.private_attributes), mutating the configured list, so a context that declared nothing private still had the previous context's private attributes redacted.Requirements
Related issues
v3lineImplementation details
Why the existing tests could not catch it
makeEventContextTestParamscreates a new client per parameter, so theContextFilteris always fresh, and every context within one parameter comes from a single factory with identical_meta.privateAttributes. A leaked private attribute is therefore always an already-expected private attribute. The existing multi-kind fixtures don't catch it either: they either set no per-context privates, or set them only on the kind that is filtered last, and the leaked names don't exist as attributes on the other kind.What the new tests do
eventContextPrivateAttributeScopinguses one client for multiple identify events, and each context carries the same three attributes (selfPrivate,globallyPrivate,visible) while differing only in what it declares private:private attributes of one context are not applied to later contexts— identify a context declaringselfPrivateprivate, then identify a different context that declares nothing private, and assertselfPrivateis still visible on the second one.private attributes of one kind are not applied to other kinds of the same context (declared by org / by user)— a multi-kind context where only one kind declaresselfPrivateprivate; the other kind must keep it. Both orderings are covered because SDKs filter the individual contexts in an arbitrary order — with the Ruby bug present, only theorgvariant fails (Ruby filtersorgfirst), so a single-ordering test would catch this only half the time.globallyPrivateis configured viaGlobalPrivateAttributesand asserted redacted in every expectation, so an SDK cannot pass by throwing away its configured private attributes along with the per-context ones.Verification
Negative control against ruby-server-sdk with the #416 fix locally reverted to
.concat(...): subtests 1 and 2 fail with the second context wrongly reportingredactedAttributes: ["selfPrivate","globallyPrivate"]; all three pass with the fix in place.Link to Devin session: https://app.devin.ai/sessions/6e3076285f2849919b966a4f801075ca
Requested by: @kinyoklion
Note
Overview
Adds three new subtests under
events/context propertiesviaeventContextPrivateAttributeScoping, hooked fromEventContexts. Existing expectations are unchanged.The harness reuses one SDK client for multiple identify events so failures like mutating the global private-attribute list (e.g. ruby-server-sdk#416) are detectable—prior cases mostly created a fresh client per scenario.
Coverage: (1) a context that marks
selfPrivateprivate must not cause a later context with no per-context privates to redactselfPrivate; (2) for multi-kind contexts, privates declared onorgorusermust not redact the same attribute on the other kind—both orderings are tested.Every assertion still expects
globallyPrivate(fromGlobalPrivateAttributes) to be redacted so SDKs cannot pass by dropping all configured privates.Reviewed by Cursor Bugbot for commit 3fa29c4. Bugbot is set up for automated code reviews on this repo. Configure here.